﻿using System;
using UnityEngine;

/// <summary>
/// 计数器，每次增加到头，会自动回0
/// </summary>
public class SmartCounter : SmartDataBase<int>
{
    public bool m_CheckOverflow = true;
    // 用于线程安全的锁对象
    private object _lock = new object();
    // 缓存的百分比值，以提高性能
    private float? _cachedPercent = null;

    Action<int> m_FullCallback = null;

    public void SetFullCallBack(Action<int> fullCallback)
    {
        m_FullCallback += fullCallback;
    }

    /// <summary>
    /// 设置当前值为指定的值
    /// </summary>
    /// <param name="nValue">要设置的新值</param>
    /// <returns>如果设置成功，则返回true；否则返回false</returns>
    public bool DoSet(int nValue)
    {
        if (Max < 0 || nValue < 0)
            return false;

        lock (_lock)
        {
            Cur = Mathf.Min(nValue, Max);
            _cachedPercent = null; // 清除缓存
        }
        return true;
    }

    /// <summary>
    /// 更新当前值，并计算溢出次数
    /// </summary>
    /// <param name="delta">增加或减少的值</param>
    /// <param name="overflowCount">溢出次数</param>
    /// <returns>如果发生溢出，则返回true；否则返回false</returns>
    private bool UpdateCur(int delta, out int overflowCount)
    {
        if (Max <= 0 || delta < 0)
        {
            overflowCount = 0;
            return false;
        }

        lock (_lock)
        {
            Cur += delta;
            if (Cur >= Max)
            {
                if (m_CheckOverflow)
                {
                    overflowCount = Cur / Max;
                    Cur %= Max;
                    _cachedPercent = null; // 清除缓存
                    m_FullCallback?.Invoke(Cur);
                    return true;
                }
                else
                {
                    overflowCount = 0;
                    return true;
                }
            }
            overflowCount = 0;
        }
        return false;
    }

    /// <summary>
    /// 增加当前值，并计算溢出次数
    /// </summary>
    /// <param name="nValue">增加的值</param>
    /// <param name="num">溢出次数</param>
    /// <returns>如果发生溢出，则返回true；否则返回false</returns>
    public bool DoRaise(int nValue, ref int num)
    {
        return UpdateCur(nValue, out num);
    }

    /// <summary>
    /// 增加当前值
    /// </summary>
    /// <param name="nValue">增加的值</param>
    /// <returns>如果发生溢出，则返回true；否则返回false</returns>
    public bool DoAdd(int nValue)
    {
        Cur += nValue;
        if (Cur >= Max)
        {
            return true;
        }
        return false;
    }
    public bool DoAdd(int nValue, ref int num)
    {
        return UpdateCur(nValue, out num);
    }
    /// <summary>
    /// 减少当前值
    /// </summary>
    /// <param name="nValue">减少的值</param>
    /// <returns>如果当前值减少到0或以下，则返回true；否则返回false</returns>
    public bool DoReduce(int nValue)
    {
        if (Max < 0 || nValue < 0)
            return false;

        lock (_lock)
        {
            Cur -= nValue;
            if (Cur <= 0)
            {
                Cur = 0;
                _cachedPercent = null; // 清除缓存
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 重新启动计数器，将当前值重置为0
    /// </summary>
    public void DoRestart()
    {
        lock (_lock)
        {
            Cur = 0;
            _cachedPercent = null; // 清除缓存
        }
    }

    /// <summary>
    /// 将当前值设置为最大值
    /// </summary>
    public void DoFull()
    {
        lock (_lock)
        {
            Cur = Max;
            _cachedPercent = null; // 清除缓存
        }
    }

    /// <summary>
    /// 获取当前值相对于最大值的百分比
    /// </summary>
    /// <returns>当前值的百分比</returns>
    public float GetPrecent()
    {
        if (Max == 0)
            return 0;

        return (float)Cur / (float)Max;
    }

    /// <summary>
    /// 返回表示当前值和最大值的字符串
    /// </summary>
    /// <returns>格式为"当前值/最大值"的字符串</returns>
    public override string ToString()
    {
        return $"{Cur}/{Max}";
    }

    /// <summary>
    /// 检查计数器是否有效，即最大值是否大于0
    /// </summary>
    /// <returns>如果最大值大于0，则返回true；否则返回false</returns>
    public bool IsValid()
    {
        return Max > 0;
    }

    /// <summary>
    /// 关闭计数器，将最大值和当前值重置为0
    /// </summary>
    public void DoClose()
    {
        lock (_lock)
        {
            Max = 0;
            Cur = 0;
            _cachedPercent = null; // 清除缓存
        }
    }
}